package com.iot.practice.designpattern.factorymethod;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * <p>ClassUtils 此类用于：</p>
 * <p>@author：hujm</p>
 * <p>@date：2021年02月01日 15:18</p>
 * <p>@remark：</p>
 */
public class ClassUtils {

    /**
     * 给一个接口，返回这个接口的所有实现类
     */
    public static List<Class> getAllClassByInterface(Class c) {

        List<Class> returnClassList = new ArrayList<>();

        // 如果不是一个接口，则不做处理
        if (c.isInterface()) {
            // 获得当前的包名
            String packageName = c.getPackage().getName();

            try {
                // 获得当前包下以及子包下的所有类
                List<Class> allClass = getClasses(packageName);
                // 判断是否是同一个接口
                for (int i = 0; i < allClass.size(); i++) {
                    // 判断是否是同一个接口
                    if (c.isAssignableFrom(allClass.get(i))) {
                        // 本身不添加进去
                        if (!c.equals(allClass.get(i))) {
                            returnClassList.add(allClass.get(i));
                        }
                    }
                }
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        return returnClassList;
    }

    private static List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException {

        List<Class> classes = new ArrayList<>();
        if (!directory.exists()) {
            return classes;
        }

        File[] files = directory.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                assert !file.getName().contains(".");
                classes.addAll(findClasses(file, packageName + "." + file.getName()));
            } else if (file.getName().endsWith(".class")) {
                classes.add(Class.forName(packageName + "." + file.getName().substring(0, file.getName().length() - 6)));
            }
        }

        return classes;
    }

    /**
     * 从一个包中查找出所有的类，在jar包中不能查找
     *
     * @param packageName 包名
     * @return 包中所有有的类
     */
    private static List<Class> getClasses(String packageName) throws IOException, ClassNotFoundException {

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        String path = packageName.replace(".", "/");
        Enumeration<URL> resources = classLoader.getResources(path);

        List<File> dirs = new ArrayList<>();;
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            dirs.add(new File(resource.getFile()));
        }

        List<Class> classes = new ArrayList<>();
        for (File dir : dirs) {
            classes.addAll(findClasses(dir, packageName));
        }

        return classes;
    }
}
